/*
** $Id: pwenc.c 27 2014-09-10 13:44:50Z chupin007@gmail.com $
** $HeadURL: http://bapps.googlecode.com/svn/trunk/src/enc/src/pwenc.c $
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <limits.h>

#define CRYPT_FILE 1
#define CRYPT_WORD 2

int main( int argc, char **argv ) {

int keylen;
char key[256], keyfile[512];
FILE *fp;
char c;
char *command, *psw, *binname, *nl;
int  cols[256];
char buff[32767], crypted[32767], selfexe[PATH_MAX], argv0[PATH_MAX], *p_buff;
int len, nfld=1, i;
unsigned nline=0, mode, newLine;
struct stat info;
pid_t pid;

  if( argc < 2 ) {
    fprintf( stderr, "wrong number of arguments\n" );
    exit( 1 );
  }

  pid = getpid();
  sprintf( selfexe, "/proc/%d/exe", pid );
  if( readlink( selfexe, argv0, PATH_MAX ) == -1 ) {
    fprintf( stderr, "readlink error\n" );
    exit( 1 );
  }

  if( strlen( argv0 ) > 506 ) {
    fprintf( stderr, "too long path for binary\n" );
    exit( 1 );
  }
  memset( keyfile, '\0', sizeof( keyfile ) );
  if( binname = strrchr( argv0, '/' ) ) {
    memcpy( keyfile, argv0, (binname-argv0+1) );
    keyfile[(binname-argv0+1)] = '\0';
    binname++;
  } else
    binname=argv0;
 
  if( sprintf( keyfile+strlen(keyfile), ".%s.key", binname ) < 0 ) {
    fprintf( stderr, "cannot prepare key file name\n" );
    exit( 1 );
  }

  command = argv[1];
  if( strcmp( command, "enc" ) != 0 && strcmp( command, "dec" ) != 0  ) {
    fprintf( stderr, "wrong command\n" );
    exit( 1 );
  }
//printf( "argc: %d\n", argc );
  if( argc > 2 && strcmp( argv[2], "file" ) == 0 )
    mode = CRYPT_FILE;
  else
    mode = CRYPT_WORD;
//printf( "after\n" );

  fp = fopen( keyfile, "r" );
  if( fp == NULL ) {
    fprintf( stderr, "cannot read key file: %s\n", keyfile );
    exit( 1 );
  }
  keylen = fread( key, 1, sizeof( key ), fp );
  if ( keylen >= 256 ) {
    fprintf( stderr, "too long key\n" );
    exit( 1 );
  }
  key[keylen] = '\0';

  if( memchr( key, '\n', keylen ) ) {
    fprintf( stderr, "new line found in key: len=%d, %s\n", keylen, key );
    exit( 1 );
  }

  crypterInit( strcmp( command, "enc" ), key );

for(;;) {
 
  p_buff = fgets( buff, sizeof(buff), stdin );
/*
  if( fgets( buff, sizeof(buff), stdin ) != buff || strlen(buff) == 0 ) {
    fprintf( stderr, "cannot read data\n" );
    exit( 1 );
  }
*/
  if( mode == CRYPT_WORD ) {
    if( p_buff != buff || strlen(buff) == 0 ) {
      fprintf( stderr, "cannot read data\n" );
      exit( 1 );
    }
    if( nl = strrchr( buff, '\r') ) *nl = '\0';
    if( nl = strrchr( buff, '\n') ) *nl = '\0';
  } else {
/*
printf( "p_buff: %d\n", p_buff );
*/
    if( !p_buff ) {
      if( ferror( stdin ) ) {
        fprintf( stderr, "cannot read data\n" );
        exit( 1 );
      }
      exit( 0 );
    }
    newLine = 0;
    if( nl = strrchr( buff, '\n') ) {
      *nl = '\0';
      newLine = 1;
    }
  }

  if( strcmp( command, "enc" ) == 0 ) {
    len = strlen( buff );
    {
      len = crypterEncrypt( nfld, buff, crypted, len );
    }
    for( i = 0; i < len; i++ ) {
      printf("%02x", (unsigned char ) crypted[i]);
    }
  } else if( strcmp( command, "dec" ) == 0 ) {
    int newval;
    char *ptrCrypted = crypted;
    len = strlen( buff );
    if( len%2 != 0 ) {
      fprintf( stderr, "bad hexadecimal string: %s (%d)\n", buff, len%2 );
      exit( 1 );
    }
    for( i = 0; i < len; i+=2 ) {
      int val1 = (unsigned char) buff[i];
      int val2 = (unsigned char) buff[i+1];
      if( val1 >= '0' && val1 <= '9' ) val1 = val1 - '0';
      else if( val1 >= 'a' && val1 <= 'f' ) val1 = val1 - 'a' + 10;
      else {
        fprintf( stderr, "bad hexadecimal string found2 (%c%c): %s\n", val1, val2, buff );
        exit( 1 );
      }
      if( val2 >= '0' && val2 <= '9' ) val2 = val2 - '0';
      else if( val2 >= 'a' && val2 <= 'f' ) val2 = val2 - 'a' + 10;
      else {
        fprintf( stderr, "bad hexadecimal string found3 (%c%c): %s\n", val1, val2, buff );
        exit( 1 );
      }
      newval = 16 * val1 + val2;
      *ptrCrypted = (unsigned char) newval;
      ptrCrypted++;
    }
    len = len/2;
    {
      len = crypterDecrypt( nfld, crypted, buff, len );
    }
    buff[len] = '\0';
    printf("%s", buff );

  } else {
    fprintf( stderr, "unexpected command: %s\n", command );
    exit( 1 );
  }
  if( mode == CRYPT_WORD ) break;
  if( newLine == 1 ) printf("\n" );
}
  exit(0);
}
